package com.whfc.mach.redis.impl;

import com.whfc.common.util.DateUtil;
import com.whfc.mach.dto.AppMachDataLogCacheDTO;
import com.whfc.mach.dto.AppMachDataLogDTO;
import com.whfc.mach.entity.AppMachDataLog;
import com.whfc.mach.redis.MachDataRedisDao;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Repository;

import java.text.MessageFormat;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Description:
 * @author: xugcheng
 * @version: 1.0
 * @date: 2019/11/25 18:52
 */
@Repository
public class MachDataRedisDaoImpl implements MachDataRedisDao {

    private static final String machDataLogKey = "mach-data-log::{0}::{1}";

    private static final int EXPIRE_HOURS = 1;

    @Autowired
    private RedisTemplate<String, AppMachDataLogCacheDTO> redisTemplate;

    @Override
    public void addMachDataLog(Integer machId, Date date, List<AppMachDataLog> logList) {
        if (logList != null && logList.size() > 0) {
            Set<AppMachDataLogCacheDTO> logCacheSet = logList.stream().map(log -> from(log)).collect(Collectors.toSet());
            this.addMachData(machId, date, logCacheSet);
        }
    }

    @Override
    public void addMachDataLogDTO(Integer machId, Date date, List<AppMachDataLogDTO> logList) {
        if (logList != null && logList.size() > 0) {
            Set<AppMachDataLogCacheDTO> logCacheSet = logList.stream().map(log -> fromDTO(log)).collect(Collectors.toSet());
            this.addMachData(machId, date, logCacheSet);
        }
    }

    @Override
    public List<AppMachDataLog> getMachDataLog(Integer machId, Date date, Date startTime, Date endTime) {
        Set<AppMachDataLogCacheDTO> logCacheSet = this.getMachData(machId, date, startTime, endTime);
        return logCacheSet.stream().map(cache -> to(cache)).collect(Collectors.toList());
    }

    @Override
    public List<AppMachDataLogDTO> getMachDataLogDTO(Integer machId, Date date, Date startTime, Date endTime) {
        Set<AppMachDataLogCacheDTO> logCacheSet = this.getMachData(machId, date, startTime, endTime);
        return logCacheSet.stream().map(cache -> toDTO(cache)).collect(Collectors.toList());
    }

    @Override
    public void delMachData(Integer machId, Date date) {
        String key = MessageFormat.format(machDataLogKey, machId, DateUtil.formatDate(date));
        redisTemplate.delete(key);
    }

    @Override
    public boolean exists(Integer machId, Date date) {
        String key = MessageFormat.format(machDataLogKey, machId, DateUtil.formatDate(date));
        return redisTemplate.hasKey(key);
    }

    /**
     * 增加缓存(内部的logCacheDTO)
     *
     * @param machId
     * @param date
     * @param logs
     */
    private void addMachData(Integer machId, Date date, Set<AppMachDataLogCacheDTO> logs) {
        String key = MessageFormat.format(machDataLogKey, machId, DateUtil.formatDate(date));
        Set<ZSetOperations.TypedTuple<AppMachDataLogCacheDTO>> tuples = logs.stream()
                .map(dto -> toTypedTuple(dto))
                .collect(Collectors.toSet());
        redisTemplate.opsForZSet().add(key, tuples);
        redisTemplate.expire(key, EXPIRE_HOURS, TimeUnit.HOURS);
    }

    /**
     * 获取缓存(内部的logCacheDTO)
     *
     * @param machId
     * @param date
     * @param startTime
     * @param endTime
     * @return
     */
    private Set<AppMachDataLogCacheDTO> getMachData(Integer machId, Date date, Date startTime, Date endTime) {
        String key = MessageFormat.format(machDataLogKey, machId, DateUtil.formatDate(date));
        Double min = timeToScore(startTime);
        Double max = timeToScore(endTime);
        return redisTemplate.opsForZSet().rangeByScore(key, min, max);
    }

    private ZSetOperations.TypedTuple<AppMachDataLogCacheDTO> toTypedTuple(AppMachDataLogCacheDTO dto) {
        Double score = timeToScore(dto.getTime());
        return new DefaultTypedTuple(dto, score);
    }

    private Double timeToScore(Date time) {
        return Double.valueOf(time.getTime() / 1000);
    }

    private AppMachDataLogCacheDTO from(AppMachDataLog log) {
        AppMachDataLogCacheDTO cacheDTO = new AppMachDataLogCacheDTO();
        BeanUtils.copyProperties(log, cacheDTO);
        return cacheDTO;
    }

    private AppMachDataLog to(AppMachDataLogCacheDTO logCache) {
        AppMachDataLog log = new AppMachDataLog();
        BeanUtils.copyProperties(logCache, log);
        return log;
    }

    private AppMachDataLogCacheDTO fromDTO(AppMachDataLogDTO log) {
        AppMachDataLogCacheDTO cacheDTO = new AppMachDataLogCacheDTO();
        BeanUtils.copyProperties(log, cacheDTO);
        return cacheDTO;
    }

    private AppMachDataLogDTO toDTO(AppMachDataLogCacheDTO logCache) {
        AppMachDataLogDTO log = new AppMachDataLogDTO();
        BeanUtils.copyProperties(logCache, log);
        return log;
    }
}
